package com.client.koshercook.server;


import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.users.*;
import com.google.gwt.user.client.rpc.IsSerializable;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

@PersistenceCapable
public class Accounts implements IsSerializable{
    @PrimaryKey
    @Persistent
    private Key key; //the account key in data store 
    
   @Persistent
   private User user; // the user identifier

   @Persistent
   private List<String> ViewedRecipes_name; // the names of recipes the user visit
   
   @Persistent
   private List<String> ViewedRecipes_link; // the links of recipes the user visit
   
   @Persistent
   private List<String> myFridge; // list of ingredients the user always keep in his home
   
   @Persistent
   private List<String> rankedRecipes_link; // list of the recipes the user rated
   
   @Persistent
   private List<Integer> rankedRecipes_num; // list of the ranks according to rankedRecipes order
   
   @Persistent
   private List<String> favorites_link; //favorites recipes links
   
   @Persistent
   private List<String> favorites_name; //favorites recipes names
   
   @Persistent
   private List<String> favUploaders_name; //favorites recipes uploader
   
   @Persistent
   private List<Integer> favUploaders_num; //user's favorite uploader
   
   @Persistent
   private boolean useFridge; // save the client request whether to use the fridge or not  
   
   /** constructor for new account */
   public Accounts(User userId){
	   user = userId;
	   this.key = KeyFactory.createKey(Accounts.class.getSimpleName(), user.getEmail());
	   myFridge = new ArrayList<String>();
	   ViewedRecipes_link = new LinkedList<String>();
	   ViewedRecipes_name = new LinkedList<String>();
	   rankedRecipes_link = new ArrayList<String>();
	   rankedRecipes_num = new ArrayList<Integer>();
	   favorites_link = new ArrayList<String>();
	   favorites_name = new ArrayList<String>();
	   favUploaders_name = new ArrayList<String>();
	   favUploaders_num = new ArrayList<Integer>();
	   useFridge = false;
   }
   
   /** constructor for copy account */
   public Accounts(Accounts acc){
	   user = acc.getUser();
	   this.key = KeyFactory.createKey(Accounts.class.getSimpleName(), user.getEmail());
	   myFridge = new ArrayList<String>();
	   myFridge.addAll(acc.getMyFridge());
	   ViewedRecipes_link = new LinkedList<String>();
	   ViewedRecipes_link.addAll(acc.getViewedRecipes_link());
	   ViewedRecipes_name = new LinkedList<String>();
	   ViewedRecipes_name.addAll(acc.getViewedRecipes_name());
	   rankedRecipes_link = new ArrayList<String>();
	   rankedRecipes_link.addAll(acc.getRankedRecipes_link());
	   rankedRecipes_num = new ArrayList<Integer>();
	   rankedRecipes_num.addAll(acc.getRankedRecipes_num());
	   favorites_link = new ArrayList<String>();
	   favorites_link.addAll(acc.getFavorites_link());
	   favorites_name = new ArrayList<String>();
	   favorites_name.addAll(acc.getFavorites_name());
	   favUploaders_name = new ArrayList<String>();
	   favUploaders_name.addAll(acc.getFavUploaders_name());
	   favUploaders_num = new ArrayList<Integer>();
	   favUploaders_num.addAll(acc.getFavUploaders_num());
	   useFridge = acc.getUserFridgeReq();
   }
    
   public String getUserNickName(){
	   return this.user.getNickname();
   }
   
   public String getUserMail(){
	   return this.user.getEmail();
   }
   
   public User getUser(){
	   return this.user;
   }

   public void setMyFridge(List<String> fridge) {
	   this.myFridge.clear();
	   this.myFridge.addAll(fridge);
   }
   
   public List<String> getMyFridge(){
	   return this.myFridge; 
   }
   
   public List<Key> getMyFridgeKeys(){
	   List<Key> res = new ArrayList<Key>();
	   for(String str : this.myFridge)
		   res.add(KeyFactory.createKey(Ingredient.class.getSimpleName(), str));
	   return res; 
   }

   public Key getKey(){
	   return this.key; 
   }
   
   public void removeAllIngredientFromMyFridge(){
	   this.myFridge = new LinkedList<String>();
   }
   
   /** add the rank of the user.
    * @pre the user hasn't ranked it yet */ 
   public void addRankRecipe(String recipe_link, int rank){
	   this.rankedRecipes_link.add(recipe_link);
	   this.rankedRecipes_num.add(rank);
   }

   /** return the rank the user gave to the recipe, if he didn't rank return 0 */
   public int getRankForRecipe(String recipe_link){
	   int res=0,i=0;
	   for(String str : this.rankedRecipes_link){
		   if(str.equals(recipe_link)) {
			   res = this.rankedRecipes_num.get(i);
			   break;
		   }
		   i++;
	   }
	   return res;
   }
   
   /** add the last visited recipe to the top of the list*/
   public void addViewedRecipe(String name, String link) {
	   //check if the link already exists in history
	   for(int i=0 ;i< ViewedRecipes_link.size() ; i++) {
		   if(ViewedRecipes_link.get(i).equals(link)) {
			   this.ViewedRecipes_link.remove(i);
			   this.ViewedRecipes_name.remove(i);
			   break;
		   }
	   }
	   //check if we reached max history length then delete last recent
	   if(ViewedRecipes_link.size()==DataStore.HISTORY_SIZE) {
		   this.ViewedRecipes_link.remove(DataStore.HISTORY_SIZE-1);
		   this.ViewedRecipes_name.remove(DataStore.HISTORY_SIZE-1);
	   }
	   
	   //add the recently visited recipe to top
	   this.ViewedRecipes_name.add(0,name);
	   this.ViewedRecipes_link.add(0,link);
   }
   
   /** clear the list of history */
   public void clearHistory() {
	   this.ViewedRecipes_link.clear();
	   this.ViewedRecipes_name.clear();
   }
   
   /** @return a list of strings including: name + "@" + link<br>
    * the list is sorted from most recent visited to last recent */
   public List<String> getHistory() {
	   List<String> res = new ArrayList<String>();
	   for(int i=0 ; i<this.ViewedRecipes_link.size() ; i++) {
		   res.add(ViewedRecipes_name.get(i)+"@"+ViewedRecipes_link.get(i));
	   }
	   return res;
   }
   
   /** add a recipe link to user's favorites, and addFavUploader.
    * @return true if added successfully, false if recipe already in fav. */
   public boolean addFavorite(String link, String name,String uploader) {
	   if(this.favorites_link.contains(link)) return false;
	   this.favorites_link.add(link);
	   this.favorites_name.add(name);
	   addFavUploader(uploader);
	   return true;
   }
   
   /** remove a recipe link from user's favorites */
   public void removeFavorite(String link,String uploader) {
	   for(int i=0 ;i< favorites_link.size() ; i++) {
		   if(favorites_link.get(i).equals(link)) {
			   this.favorites_link.remove(i);
			   this.favorites_name.remove(i);
			   removeFavUploader(uploader);
			   break;
		   }
	   }
   }
   
   /** @return a list of strings including: name + "@" + link<br>*/
   public List<String> getFavoriteRecipes() {
	   List<String> res = new ArrayList<String>();
	   for(int i=0 ; i<this.favorites_link.size() ; i++) {
		   res.add(favorites_name.get(i)+"@"+favorites_link.get(i));
	   }
	   return res;
   }
   
   /** add the uploader's num +1. also creates new if needed*/
   public void addFavUploader(String uploader) {
	   for(int i=0 ;i< favUploaders_name.size() ; i++) {
		   if(favUploaders_name.get(i).equals(uploader)) {
			   favUploaders_num.set(i,favUploaders_num.get(i)+1);
			   return;
		   }
	   }
	   favUploaders_name.add(uploader);
	   favUploaders_num.add(1);
   }
   
   /** remove the uploader's num -1. also deletes if needed*/
   public void removeFavUploader(String uploader) {
	   for(int i=0 ;i< favUploaders_name.size() ; i++) {
		   if(favUploaders_name.get(i).equals(uploader)) {
			   if(favUploaders_num.get(i)==1) {
				   favUploaders_num.remove(i);
				   favUploaders_name.remove(i);
			   }
			   else favUploaders_num.set(i,favUploaders_num.get(i)-1);
			   return;
		   }
	   }
   }
   
   /** get the number of favorites recipes the uploader wrote */
   public int getUploaderPopularity(String uploader) {
	   for(int i=0 ;i< favUploaders_name.size() ; i++)
		   if(favUploaders_name.get(i).equals(uploader)) 
			   return favUploaders_num.get(i);
	   return 0;
   }
   
   public void setViewedRecipes_name(List<String> viewedRecipes_name) {
	ViewedRecipes_name = viewedRecipes_name;
	}
	
	public List<String> getViewedRecipes_name() {
		return ViewedRecipes_name;
	}

	public void setViewedRecipes_link(List<String> viewedRecipes_link) {
		ViewedRecipes_link = viewedRecipes_link;
	}

	public List<String> getViewedRecipes_link() {
		return ViewedRecipes_link;
	}

	public void setRankedRecipes_link(List<String> rankedRecipes_link) {
		this.rankedRecipes_link = rankedRecipes_link;
	}

	public List<String> getRankedRecipes_link() {
		return rankedRecipes_link;
	}

	public void setRankedRecipes_num(List<Integer> rankedRecipes_num) {
		this.rankedRecipes_num = rankedRecipes_num;
	}

	public List<Integer> getRankedRecipes_num() {
		return rankedRecipes_num;
	}

	public void setFavorites_link(List<String> favorites_link) {
		this.favorites_link = favorites_link;
	}

	public List<String> getFavorites_link() {
		return favorites_link;
	}

	public void setFavorites_name(List<String> favorites_name) {
		this.favorites_name = favorites_name;
	}

	public List<String> getFavorites_name() {
		return favorites_name;
	}

	public void setFavUploaders_name(List<String> favUploaders_name) {
		this.favUploaders_name = favUploaders_name;
	}

	public List<String> getFavUploaders_name() {
		return favUploaders_name;
	}

	public void setFavUploaders_num(List<Integer> favUploaders_num) {
		this.favUploaders_num = favUploaders_num;
	}

	public List<Integer> getFavUploaders_num() {
		return favUploaders_num;
	}

	
	
	public boolean getUserFridgeReq(){
	   return this.useFridge;
	  }
	   
	public void setUserFridgeReq(boolean req){
		this.useFridge = req;
	}
}

